]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOS9/Mac OS Test Searcher.c
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSMacOS9 / Mac OS Test Searcher.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: Mac\040OS\040Test\040Searcher.c,v $
28 Revision 1.17 2004/06/10 04:37:27 cheshire
29 Add new parameter in mDNS_GetDomains()
30
31 Revision 1.16 2004/03/12 21:30:25 cheshire
32 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
33 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
34
35 Revision 1.15 2004/01/24 23:55:15 cheshire
36 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
37
38 Revision 1.14 2003/11/14 21:27:09 cheshire
39 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
40 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
41
42 Revision 1.13 2003/08/14 02:19:54 cheshire
43 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
44
45 Revision 1.12 2003/08/12 19:56:24 cheshire
46 Update to APSL 2.0
47
48 */
49
50 #include <stdio.h> // For printf()
51 #include <Events.h> // For WaitNextEvent()
52 #include <SIOUX.h> // For SIOUXHandleOneEvent()
53
54 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
55 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
56
57 typedef struct
58 {
59 OTLIFO serviceinfolist;
60 Boolean headerPrinted;
61 Boolean lostRecords;
62 } SearcherServices;
63
64 typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linkedServiceInfo;
65
66 // These don't have to be globals, but their memory does need to remain valid for as
67 // long as the search is going on. They are declared as globals here for simplicity.
68 #define RR_CACHE_SIZE 1000
69 static CacheRecord rrcachestorage[RR_CACHE_SIZE];
70 static mDNS mDNSStorage;
71 static mDNS_PlatformSupport PlatformSupportStorage;
72 static SearcherServices services;
73 static DNSQuestion browsequestion, domainquestion;
74
75 // PrintServiceInfo prints the service information to standard out
76 // A real application might want to do something else with the information
77 static void PrintServiceInfo(SearcherServices *services)
78 {
79 OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist));
80
81 while (link)
82 {
83 linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link);
84 ServiceInfo *s = &ls->i;
85
86 if (!services->headerPrinted)
87 {
88 printf("%-55s Type Domain IP Address Port Info\n", "Name");
89 services->headerPrinted = true;
90 }
91
92 if (ls->dom)
93 {
94 char c_dom[MAX_ESCAPED_DOMAIN_NAME];
95 ConvertDomainNameToCString(&s->name, c_dom);
96 if (ls->add) printf("%-55s available for browsing\n", c_dom);
97 else printf("%-55s no longer available for browsing\n", c_dom);
98 }
99 else
100 {
101 domainlabel name;
102 domainname type, domain;
103 char c_name[MAX_DOMAIN_LABEL+1], c_type[MAX_ESCAPED_DOMAIN_NAME], c_dom[MAX_ESCAPED_DOMAIN_NAME], c_ip[20];
104 DeconstructServiceName(&s->name, &name, &type, &domain);
105 ConvertDomainLabelToCString_unescaped(&name, c_name);
106 ConvertDomainNameToCString(&type, c_type);
107 ConvertDomainNameToCString(&domain, c_dom);
108 sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]);
109
110 printf("%-55s %-16s %-14s ", c_name, c_type, c_dom);
111 if (ls->add) printf("%-15s %5d %#s\n", c_ip, mDNSVal16(s->port), s->TXTinfo);
112 else printf("Removed\n");
113 }
114
115 link = link->fNext;
116 OTFreeMem(ls);
117 }
118 }
119
120 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
121 // enqueues a record for PrintServiceInfo() to print.
122 // Note, a browsing application would *not* normally need to get all this information --
123 // all it needs is the name, to display to the user.
124 // Finding out the address, port, and txtinfo should be deferred to the time that the user
125 // actually needs to contact the service to use it.
126 static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
127 {
128 SearcherServices *services = (SearcherServices *)query->ServiceInfoQueryContext;
129 linkedServiceInfo *info = (linkedServiceInfo *)(query->info);
130 if (query->info->ip.type == mDNSAddrType_IPv4)
131 {
132 mDNS_StopResolveService(m, query); // For this test code, one answer is sufficient
133 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
134 OTFreeMem(query);
135 }
136 }
137
138 // When a new named instance of a service is found, FoundInstance() is called.
139 // In this sample code we turn around and immediately issue a query to resolve that service name to
140 // find its address, port, and txtinfo, but a normal browing application would just display the name.
141 static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
142 {
143 #pragma unused (question)
144 SearcherServices *services = (SearcherServices *)question->QuestionContext;
145 linkedServiceInfo *info;
146
147 debugf("FoundInstance %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
148
149 if (answer->rrtype != kDNSType_PTR) return;
150 if (!services) { debugf("FoundInstance: services is NULL"); return; }
151
152 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
153 if (!info) { services->lostRecords = true; return; }
154
155 info->i.name = answer->rdata->u.name;
156 info->i.InterfaceID = answer->InterfaceID;
157 info->i.ip.type = mDNSAddrType_IPv4;
158 info->i.ip.ip.v4 = zeroIPAddr;
159 info->i.port = zeroIPPort;
160 info->add = AddRecord;
161 info->dom = mDNSfalse;
162
163 if (!AddRecord) // If TTL == 0 we're deleting a service,
164 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
165 else // else we're adding a new service
166 {
167 ServiceInfoQuery *q = (ServiceInfoQuery *)OTAllocMem(sizeof(ServiceInfoQuery));
168 if (!q) { OTFreeMem(info); services->lostRecords = true; return; }
169 mDNS_StartResolveService(m, q, &info->i, FoundInstanceInfo, services);
170 }
171 }
172
173 static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
174 {
175 #pragma unused (m)
176 #pragma unused (question)
177 SearcherServices *services = (SearcherServices *)question->QuestionContext;
178 linkedServiceInfo *info;
179
180 debugf("FoundDomain %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
181
182 if (answer->rrtype != kDNSType_PTR) return;
183 if (!services) { debugf("FoundDomain: services is NULL"); return; }
184
185 info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo));
186 if (!info) { services->lostRecords = true; return; }
187
188 info->i.name = answer->rdata->u.name;
189 info->i.InterfaceID = answer->InterfaceID;
190 info->i.ip.type = mDNSAddrType_IPv4;
191 info->i.ip.ip.v4 = zeroIPAddr;
192 info->i.port = zeroIPPort;
193 info->add = AddRecord;
194 info->dom = mDNStrue;
195
196 OTLIFOEnqueue(&services->serviceinfolist, &info->link);
197 }
198
199 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
200 static Boolean YieldSomeTime(UInt32 milliseconds)
201 {
202 extern Boolean SIOUXQuitting;
203 EventRecord e;
204 WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL);
205 SIOUXHandleOneEvent(&e);
206 return(SIOUXQuitting);
207 }
208
209 int main()
210 {
211 mStatus err;
212 Boolean DoneSetup = false;
213 void *tempmem;
214
215 SIOUXSettings.asktosaveonclose = false;
216 SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher";
217 SIOUXSettings.rows = 40;
218 SIOUXSettings.columns = 132;
219
220 printf("Multicast DNS Searcher\n\n");
221 printf("This software reports errors using MacsBug breaks,\n");
222 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
223 printf("******************************************************************************\n");
224
225 err = InitOpenTransport();
226 if (err) { debugf("InitOpenTransport failed %d", err); return(err); }
227
228 err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE,
229 mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
230 if (err) return(err);
231
232 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
233 tempmem = OTAllocMem(0x10000);
234 if (tempmem) OTFreeMem(tempmem);
235 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
236
237 services.serviceinfolist.fHead = NULL;
238 services.headerPrinted = false;
239 services.lostRecords = false;
240
241 while (!YieldSomeTime(35))
242 {
243 #if MDNS_ONLYSYSTEMTASK
244 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
245 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
246 extern void mDNSPlatformIdle(mDNS *const m);
247 mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version
248 #endif
249 if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup)
250 {
251 domainname srvtype, srvdom;
252 DoneSetup = true;
253 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
254 MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp.");
255 MakeDomainNameFromDNSNameString(&srvdom, "local.");
256 err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, FoundInstance, &services);
257 if (err) break;
258 err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, NULL, mDNSInterface_Any, FoundDomain, &services);
259 if (err) break;
260 }
261
262 if (services.serviceinfolist.fHead)
263 PrintServiceInfo(&services);
264
265 if (services.lostRecords)
266 {
267 services.lostRecords = false;
268 printf("**** Warning: Out of memory: Records have been missed.\n");
269 }
270 }
271
272 mDNS_StopBrowse(&mDNSStorage, &browsequestion);
273 mDNS_Close(&mDNSStorage);
274 return(0);
275 }